home *** CD-ROM | disk | FTP | other *** search
- int
- do_unpack(TARG,gimme,arglast)
- STR *TARG;
- int gimme;
- int *arglast;
- {
- STR **st = stack->ary_array;
- register int sp = arglast[0] + 1;
- register char *pat = str_get(st[sp++]);
- register char *s = str_get(st[sp]);
- char *strend = s + st[sp--]->str_cur;
- char *strbeg = s;
- register char *patend = pat + st[sp]->str_cur;
- int datumtype;
- register int len;
- register int bits;
-
- /* These must not be in registers: */
- short ashort;
- int aint;
- long along;
- #ifdef QUAD
- quad aquad;
- #endif
- unsigned short aushort;
- unsigned int auint;
- unsigned long aulong;
- #ifdef QUAD
- unsigned quad auquad;
- #endif
- char *aptr;
- float afloat;
- double adouble;
- int checksum = 0;
- unsigned long culong;
- double cdouble;
-
- if (gimme != G_ARRAY) { /* arrange to do first one only */
- /*SUPPRESS 530*/
- for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
- if (index("aAbBhH", *patend) || *pat == '%') {
- patend++;
- while (isDIGIT(*patend) || *patend == '*')
- patend++;
- }
- else
- patend++;
- }
- sp--;
- while (pat < patend) {
- reparse:
- datumtype = *pat++;
- if (pat >= patend)
- len = 1;
- else if (*pat == '*') {
- len = strend - strbeg; /* long enough */
- pat++;
- }
- else if (isDIGIT(*pat)) {
- len = *pat++ - '0';
- while (isDIGIT(*pat))
- len = (len * 10) + (*pat++ - '0');
- }
- else
- len = (datumtype != '@');
- switch(datumtype) {
- default:
- break;
- case '%':
- if (len == 1 && pat[-1] != '1')
- len = 16;
- checksum = len;
- culong = 0;
- cdouble = 0;
- if (pat < patend)
- goto reparse;
- break;
- case '@':
- if (len > strend - strbeg)
- fatal("@ outside of string");
- s = strbeg + len;
- break;
- case 'X':
- if (len > s - strbeg)
- fatal("X outside of string");
- s -= len;
- break;
- case 'x':
- if (len > strend - s)
- fatal("x outside of string");
- s += len;
- break;
- case 'A':
- case 'a':
- if (len > strend - s)
- len = strend - s;
- if (checksum)
- goto uchar_checksum;
- TARG = Str_new(35,len);
- str_nset(TARG,s,len);
- s += len;
- if (datumtype == 'A') {
- aptr = s; /* borrow register */
- s = TARG->str_ptr + len - 1;
- while (s >= TARG->str_ptr && (!*s || isSPACE(*s)))
- s--;
- *++s = '\0';
- TARG->str_cur = s - TARG->str_ptr;
- s = aptr; /* unborrow register */
- }
- (void)astore(stack, ++sp, str_2mortal(TARG));
- break;
- case 'B':
- case 'b':
- if (pat[-1] == '*' || len > (strend - s) * 8)
- len = (strend - s) * 8;
- TARG = Str_new(35, len + 1);
- TARG->str_cur = len;
- TARG->str_pok = 1;
- aptr = pat; /* borrow register */
- pat = TARG->str_ptr;
- if (datumtype == 'b') {
- aint = len;
- for (len = 0; len < aint; len++) {
- if (len & 7) /*SUPPRESS 595*/
- bits >>= 1;
- else
- bits = *s++;
- *pat++ = '0' + (bits & 1);
- }
- }
- else {
- aint = len;
- for (len = 0; len < aint; len++) {
- if (len & 7)
- bits <<= 1;
- else
- bits = *s++;
- *pat++ = '0' + ((bits & 128) != 0);
- }
- }
- *pat = '\0';
- pat = aptr; /* unborrow register */
- (void)astore(stack, ++sp, str_2mortal(TARG));
- break;
- case 'H':
- case 'h':
- if (pat[-1] == '*' || len > (strend - s) * 2)
- len = (strend - s) * 2;
- TARG = Str_new(35, len + 1);
- TARG->str_cur = len;
- TARG->str_pok = 1;
- aptr = pat; /* borrow register */
- pat = TARG->str_ptr;
- if (datumtype == 'h') {
- aint = len;
- for (len = 0; len < aint; len++) {
- if (len & 1)
- bits >>= 4;
- else
- bits = *s++;
- *pat++ = hexdigit[bits & 15];
- }
- }
- else {
- aint = len;
- for (len = 0; len < aint; len++) {
- if (len & 1)
- bits <<= 4;
- else
- bits = *s++;
- *pat++ = hexdigit[(bits >> 4) & 15];
- }
- }
- *pat = '\0';
- pat = aptr; /* unborrow register */
- (void)astore(stack, ++sp, str_2mortal(TARG));
- break;
- case 'c':
- if (len > strend - s)
- len = strend - s;
- if (checksum) {
- while (len-- > 0) {
- aint = *s++;
- if (aint >= 128) /* fake up signed chars */
- aint -= 256;
- culong += aint;
- }
- }
- else {
- while (len-- > 0) {
- aint = *s++;
- if (aint >= 128) /* fake up signed chars */
- aint -= 256;
- TARG = Str_new(36,0);
- str_numset(TARG,(double)aint);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'C':
- if (len > strend - s)
- len = strend - s;
- if (checksum) {
- uchar_checksum:
- while (len-- > 0) {
- auint = *s++ & 255;
- culong += auint;
- }
- }
- else {
- while (len-- > 0) {
- auint = *s++ & 255;
- TARG = Str_new(37,0);
- str_numset(TARG,(double)auint);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 's':
- along = (strend - s) / sizeof(short);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&ashort,1,short);
- s += sizeof(short);
- culong += ashort;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&ashort,1,short);
- s += sizeof(short);
- TARG = Str_new(38,0);
- str_numset(TARG,(double)ashort);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'v':
- case 'n':
- case 'S':
- along = (strend - s) / sizeof(unsigned short);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&aushort,1,unsigned short);
- s += sizeof(unsigned short);
- #ifdef HAS_NTOHS
- if (datumtype == 'n')
- aushort = ntohs(aushort);
- #endif
- #ifdef HAS_VTOHS
- if (datumtype == 'v')
- aushort = vtohs(aushort);
- #endif
- culong += aushort;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&aushort,1,unsigned short);
- s += sizeof(unsigned short);
- TARG = Str_new(39,0);
- #ifdef HAS_NTOHS
- if (datumtype == 'n')
- aushort = ntohs(aushort);
- #endif
- #ifdef HAS_VTOHS
- if (datumtype == 'v')
- aushort = vtohs(aushort);
- #endif
- str_numset(TARG,(double)aushort);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'i':
- along = (strend - s) / sizeof(int);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&aint,1,int);
- s += sizeof(int);
- if (checksum > 32)
- cdouble += (double)aint;
- else
- culong += aint;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&aint,1,int);
- s += sizeof(int);
- TARG = Str_new(40,0);
- str_numset(TARG,(double)aint);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'I':
- along = (strend - s) / sizeof(unsigned int);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&auint,1,unsigned int);
- s += sizeof(unsigned int);
- if (checksum > 32)
- cdouble += (double)auint;
- else
- culong += auint;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&auint,1,unsigned int);
- s += sizeof(unsigned int);
- TARG = Str_new(41,0);
- str_numset(TARG,(double)auint);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'l':
- along = (strend - s) / sizeof(long);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&along,1,long);
- s += sizeof(long);
- if (checksum > 32)
- cdouble += (double)along;
- else
- culong += along;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&along,1,long);
- s += sizeof(long);
- TARG = Str_new(42,0);
- str_numset(TARG,(double)along);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'V':
- case 'N':
- case 'L':
- along = (strend - s) / sizeof(unsigned long);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s,&aulong,1,unsigned long);
- s += sizeof(unsigned long);
- #ifdef HAS_NTOHL
- if (datumtype == 'N')
- aulong = ntohl(aulong);
- #endif
- #ifdef HAS_VTOHL
- if (datumtype == 'V')
- aulong = vtohl(aulong);
- #endif
- if (checksum > 32)
- cdouble += (double)aulong;
- else
- culong += aulong;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s,&aulong,1,unsigned long);
- s += sizeof(unsigned long);
- TARG = Str_new(43,0);
- #ifdef HAS_NTOHL
- if (datumtype == 'N')
- aulong = ntohl(aulong);
- #endif
- #ifdef HAS_VTOHL
- if (datumtype == 'V')
- aulong = vtohl(aulong);
- #endif
- str_numset(TARG,(double)aulong);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'p':
- along = (strend - s) / sizeof(char*);
- if (len > along)
- len = along;
- while (len-- > 0) {
- if (sizeof(char*) > strend - s)
- break;
- else {
- Copy(s,&aptr,1,char*);
- s += sizeof(char*);
- }
- TARG = Str_new(44,0);
- if (aptr)
- str_set(TARG,aptr);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- break;
- #ifdef QUAD
- case 'q':
- while (len-- > 0) {
- if (s + sizeof(quad) > strend)
- aquad = 0;
- else {
- Copy(s,&aquad,1,quad);
- s += sizeof(quad);
- }
- TARG = Str_new(42,0);
- str_numset(TARG,(double)aquad);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- break;
- case 'Q':
- while (len-- > 0) {
- if (s + sizeof(unsigned quad) > strend)
- auquad = 0;
- else {
- Copy(s,&auquad,1,unsigned quad);
- s += sizeof(unsigned quad);
- }
- TARG = Str_new(43,0);
- str_numset(TARG,(double)auquad);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- break;
- #endif
- /* float and double added gnb@melba.bby.oz.au 22/11/89 */
- case 'f':
- case 'F':
- along = (strend - s) / sizeof(float);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s, &afloat,1, float);
- s += sizeof(float);
- cdouble += afloat;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s, &afloat,1, float);
- s += sizeof(float);
- TARG = Str_new(47, 0);
- str_numset(TARG, (double)afloat);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'd':
- case 'D':
- along = (strend - s) / sizeof(double);
- if (len > along)
- len = along;
- if (checksum) {
- while (len-- > 0) {
- Copy(s, &adouble,1, double);
- s += sizeof(double);
- cdouble += adouble;
- }
- }
- else {
- while (len-- > 0) {
- Copy(s, &adouble,1, double);
- s += sizeof(double);
- TARG = Str_new(48, 0);
- str_numset(TARG, (double)adouble);
- (void)astore(stack, ++sp, str_2mortal(TARG));
- }
- }
- break;
- case 'u':
- along = (strend - s) * 3 / 4;
- TARG = Str_new(42,along);
- while (s < strend && *s > ' ' && *s < 'a') {
- int a,b,c,d;
- char hunk[4];
-
- hunk[3] = '\0';
- len = (*s++ - ' ') & 077;
- while (len > 0) {
- if (s < strend && *s >= ' ')
- a = (*s++ - ' ') & 077;
- else
- a = 0;
- if (s < strend && *s >= ' ')
- b = (*s++ - ' ') & 077;
- else
- b = 0;
- if (s < strend && *s >= ' ')
- c = (*s++ - ' ') & 077;
- else
- c = 0;
- if (s < strend && *s >= ' ')
- d = (*s++ - ' ') & 077;
- else
- d = 0;
- hunk[0] = a << 2 | b >> 4;
- hunk[1] = b << 4 | c >> 2;
- hunk[2] = c << 6 | d;
- str_ncat(TARG,hunk, len > 3 ? 3 : len);
- len -= 3;
- }
- if (*s == '\n')
- s++;
- else if (s[1] == '\n') /* possible checksum byte */
- s += 2;
- }
- (void)astore(stack, ++sp, str_2mortal(TARG));
- break;
- }
- if (checksum) {
- TARG = Str_new(42,0);
- if (index("fFdD", datumtype) ||
- (checksum > 32 && index("iIlLN", datumtype)) ) {
- double modf();
- double trouble;
-
- adouble = 1.0;
- while (checksum >= 16) {
- checksum -= 16;
- adouble *= 65536.0;
- }
- while (checksum >= 4) {
- checksum -= 4;
- adouble *= 16.0;
- }
- while (checksum--)
- adouble *= 2.0;
- along = (1 << checksum) - 1;
- while (cdouble < 0.0)
- cdouble += adouble;
- cdouble = modf(cdouble / adouble, &trouble) * adouble;
- str_numset(TARG,cdouble);
- }
- else {
- if (checksum < 32) {
- along = (1 << checksum) - 1;
- culong &= (unsigned long)along;
- }
- str_numset(TARG,(double)culong);
- }
- (void)astore(stack, ++sp, str_2mortal(TARG));
- checksum = 0;
- }
- }
- return sp;
- }
-
-